#pragma once
#include <functional>
#include <memory>
#include "Socket.h"

namespace xncc {
namespace foundation {
    class EventLoop;
    class Channel;
    /// connector 会被绑定到loop中，如果持有connector智能指针的类释放了,
    class Connector : public std::enable_shared_from_this<Connector>
    {
      public:
        using NewConnectionCallback = std::function<void(int)>;
        Connector(EventLoop* loop, std::shared_ptr<XnccAddress> serverAddr);
        ~Connector();

        Connector(const Connector&)             = delete;
        Connector(const Connector&&)            = delete;
        Connector& operator=(const Connector&)  = delete;
        Connector& operator=(const Connector&&) = delete;

        void setNewConnectionCallback(const NewConnectionCallback& conn_cb) { newConnectionCallback_ = conn_cb; }
        void start();    // can be called in any thread
        void restart();  // must be called in loop thread
        void stop();     // can be called in any thread
        std::shared_ptr<XnccAddress> serverAddress() const { return serverAddr_; }
        void                         shutdown(std::shared_ptr<Channel> channel);
        void                         setRetryInterval(int retry_ms) { retryDelayMs_ = retry_ms; }

      private:
        enum CONN_STATE : uint8_t
        {
            DISCONNECTED,
            CONNECTING,
            CONNECTED
        };
        void setState(CONN_STATE s) { state_ = s; }
        void startInLoop(bool needSleep);
        void stopInLoop();
        void shutdownInLoop(const std::shared_ptr<Channel>& channel);
        void connect();
        void retry(int sockfd);
        void handleError();
        void handleWrite();
        void resetChannel();
        int  removeAndResetChannel();
        void connecting(int sockfd);

        EventLoop*                   loop_;
        std::shared_ptr<XnccAddress> serverAddr_;
        bool                         connect_;
        CONN_STATE                   state_;
        std::shared_ptr<Channel>     channel_;
        NewConnectionCallback        newConnectionCallback_;
        int                          retryDelayMs_;
    };
}  // namespace foundation
}  // namespace xncc